"use strict";

var $ = require("jquery"),
    executeAsyncMock = require("../../../helpers/executeAsyncMock.js"),
    keyboardMock = require("../../../helpers/keyboardMock.js"),
    DataSource = require("data/data_source/data_source").DataSource,
    ArrayStore = require("data/array_store");

require("ui/list");

var LIST_ITEM_CLASS = "dx-list-item";

var toSelector = function(cssClass) {
    return "." + cssClass;
};

QUnit.module("flat index");

QUnit.test("index should be correct for plain list", function(assert) {
    var items = [{ a: 0 }, { a: 1 }];

    var $list = $("#templated-list").dxList({
            items: items
        }),
        list = $list.dxList("instance");

    var $items = $list.find(toSelector(LIST_ITEM_CLASS)),
        $item = $items.eq(1);

    assert.equal(list.getFlatIndexByItemElement($item.get(0)), 1, "index correct");
    assert.equal(list.getFlatIndexByItemElement($item), 1, "index correct");
});

QUnit.test("index should be correct for grouped list", function(assert) {
    var items = [
        {
            key: 'first',
            items: [{ a: 0 }, { a: 1 }, { a: 2 }]
        },
        {
            key: 'second',
            items: [{ a: 3 }, { a: 4 }, { a: 5 }]
        }
    ];

    var $list = $("#templated-list").dxList({
            items: items,
            grouped: true
        }),
        list = $list.dxList("instance");

    var $items = $list.find(toSelector(LIST_ITEM_CLASS)),
        $item = $items.eq(5);

    assert.equal(list.getFlatIndexByItemElement($item.get(0)), 5, "index correct");
    assert.equal(list.getFlatIndexByItemElement($item), 5, "index correct");
});

QUnit.test("it should be possible to select an item in the grouped list by primitive index", function(assert) {
    var items = [
        {
            key: 'first',
            items: [{ a: 0 }, { a: 1 }]
        },
        {
            key: 'second',
            items: [{ a: 2 }, { a: 3 }]
        }
    ];

    var $list = $("#templated-list").dxList({
            items: items,
            selectionMode: "single",
            selectedIndex: 2,
            grouped: true
        }),
        list = $list.dxList("instance");

    var $items = $list.find(toSelector(LIST_ITEM_CLASS));

    assert.ok($items.eq(2).hasClass(LIST_ITEM_SELECTED_CLASS), "correct item is selected");
    assert.deepEqual(list.option("selectedItem"), { key: 'second', items: [{ a: 2 }] }, "selectedItem is correct");
    assert.deepEqual(list.option("selectedItems"), [{ key: 'second', items: [{ a: 2 }] }], "selectedItems is correct");

    list.option("selectedIndex", 1);
    assert.ok($items.eq(1).hasClass(LIST_ITEM_SELECTED_CLASS), "correct item is selected");
    assert.deepEqual(list.option("selectedItem"), { key: 'first', items: [{ a: 1 }] }, "selectedItem is correct");
    assert.deepEqual(list.option("selectedItems"), [{ key: 'first', items: [{ a: 1 }] }], "selectedItems is correct");
});

QUnit.test("item should be correct for plain list", function(assert) {
    var items = [{ a: 0 }, { a: 1 }];

    var $list = $("#templated-list").dxList({
            items: items
        }),
        list = $list.dxList("instance");

    var $items = $list.find(toSelector(LIST_ITEM_CLASS)),
        $item = $items.eq(1);

    assert.equal(list.getItemElementByFlatIndex(1).get(0), $item.get(0), "item correct");
});

QUnit.test("index should be correct for grouped list", function(assert) {
    var items = [
        {
            key: 'first',
            items: [{ a: 0 }, { a: 1 }, { a: 2 }]
        },
        {
            key: 'second',
            items: [{ a: 3 }, { a: 4 }, { a: 5 }]
        }
    ];

    var $list = $("#templated-list").dxList({
            items: items,
            grouped: true
        }),
        list = $list.dxList("instance");

    var $items = $list.find(toSelector(LIST_ITEM_CLASS)),
        $item = $items.eq(5);

    assert.equal(list.getItemElementByFlatIndex(5).get(0), $item.get(0), "item correct");
});


var groupedListData = {
    data: [
        {
            key: 'first',
            items: [{ a: 0 }, { a: 1 }, { a: 2 }]
        },
        {
            key: 'second',
            items: [{ a: 3 }, { a: 4 }, { a: 5 }]
        },
        {
            key: 'third',
            items: [{ a: 6 }, { a: 7 }, { a: 8 }]
        }
    ],
    itemsAfterDelete: [
        {
            key: 'first',
            items: [{ a: 0 }, { a: 1 }, { a: 2 }]
        },
        {
            key: 'second',
            items: [{ a: 3 }, { a: 4 }]
        },
        {
            key: 'third',
            items: [{ a: 6 }, { a: 7 }, { a: 8 }]
        }
    ]
};


QUnit.module("deleting in grouped list");

QUnit.test("deleteItem should remove item by node", function(assert) {
    var $list = $("#templated-list").dxList({
            items: groupedListData.data,
            grouped: true,
            editEnabled: true
        }),
        list = $list.dxList("instance");

    var $groups = $list.find(toSelector(LIST_GROUP_CLASS));

    list.deleteItem($groups.eq(1).find(toSelector(LIST_ITEM_CLASS)).eq(2));

    assert.deepEqual(list.option("items"), groupedListData.itemsAfterDelete, "item deleted");
});

QUnit.test("deleteItem should remove item by index", function(assert) {
    var $list = $("#templated-list").dxList({
            items: groupedListData.data,
            grouped: true,
            editEnabled: true
        }),
        list = $list.dxList("instance");

    list.deleteItem({ group: 1, item: 2 });

    assert.deepEqual(list.option("items"), groupedListData.itemsAfterDelete, "item deleted");
});

QUnit.test("deleteItem should remove item by index", function(assert) {
    var $list = $("#templated-list").dxList({
            items: groupedListData.data,
            grouped: true,
            editEnabled: true
        }),
        list = $list.dxList("instance");

    list.deleteItem({ group: 1, item: 2 });

    assert.deepEqual(list.option("items"), groupedListData.itemsAfterDelete, "item deleted");
});

QUnit.module("keyboard navigation", {
    beforeEach: function() {
        this.clock = sinon.useFakeTimers();
    },
    afterEach: function() {
        this.clock.restore();
    }
});

QUnit.test("item deletion by keyboard", function(assert) {
    var items = ["1", "2", "3"];

    var $list = $("#list").dxList({
            items: items,
            editEnabled: true,
            allowItemDeleting: false,
            focusStateEnabled: true
        }),
        list = $list.dxList("instance");

    var keyboard = keyboardMock($list);

    $list.focusin();
    keyboard.keyDown("del");

    assert.deepEqual(list.option("items"), items, "deletion by keyboard is impossible if 'allowItemDeleting' = false ");

    list.option("allowItemDeleting", true);
    list.option("focusedElement", $list.find("." + LIST_ITEM_CLASS).eq(1));

    keyboard.keyDown("del");

    assert.deepEqual(list.option("items"), ["1", "3"], "item was deleted");
});

QUnit.test("items reordering by keyboard", function(assert) {
    var items = ["1", "2", "3"];

    var $list = $("#list").dxList({
            items: items,
            editEnabled: true,
            allowItemReordering: false,
            focusStateEnabled: true
        }),
        list = $list.dxList("instance"),
        $lastItem = $list.find("." + LIST_ITEM_CLASS).eq(2);

    $lastItem.trigger("dxpointerdown");
    this.clock.tick();
    $lastItem.trigger($.Event("keydown", { which: 38, shiftKey: true }));

    assert.deepEqual(list.option("items"), items, "reordering by keyboard is impossible if 'allowItemReordering' = false ");

    list.option("allowItemReordering", true);

    $lastItem = $list.find("." + LIST_ITEM_CLASS).eq(2);
    $lastItem.trigger("dxpointerdown");
    this.clock.tick();
    $list.trigger($.Event("keydown", { which: 38, shiftKey: true }));

    assert.deepEqual(list.option("items"), ["1", "3", "2"], "items were reordered");

    $lastItem.trigger($.Event("keydown", { which: 40, shiftKey: true }));

    assert.deepEqual(list.option("items"), items, "items were reordered");
});


QUnit.module("deleting in grouped list with dataSource", {
    beforeEach: function() {
        executeAsyncMock.setup();
    },
    afterEach: function() {
        executeAsyncMock.teardown();
    }
});

QUnit.test("deleteItem shouldn't load data", function(assert) {
    var dataSource = new DataSource({
        store: groupedListData.data,
        pageSize: 1
    });

    var $list = $("#list").height(60).dxList({
        dataSource: dataSource,
        grouped: true,
        editEnabled: true
    });

    var $listItems = $("." + LIST_ITEM_CLASS, $list);

    $list.dxList("deleteItem", { group: 0, item: 1 }).done(function() {
        var $newListItems = $("." + LIST_ITEM_CLASS, $list);
        assert.equal($listItems.length, $newListItems.length + 1, "new item wasn't loaded");
    });
});


QUnit.module("selectAll methods");

QUnit.test("selectAll/unselectAll for 'page' selectAllMode", function(assert) {
    var items = [1, 2, 3, 4, 5];
    var ds = new DataSource({
        store: items,
        pageSize: 2,
        paginate: true
    });

    var $element = $("#list").dxList({
        dataSource: ds,
        pageLoadMode: "nextButton",
        selectionMode: "multiple",
        selectAllMode: "page"
    });

    var instance = $element.dxList("instance");

    instance.selectAll();

    assert.deepEqual(instance.option("selectedItems"), items.slice(0, 2), "selected items is correct");

    instance.unselectAll();

    assert.deepEqual(instance.option("selectedItems"), [], "selected items is empty");
});

QUnit.test("selectAll/unselectAll for 'allPages' selectAllMode", function(assert) {
    var items = [1, 2, 3, 4, 5];
    var loading = sinon.spy();
    var ds = new DataSource({
        store: {
            type: "array",
            data: items,
            onLoading: loading
        },
        pageSize: 2,
        paginate: true
    });

    var $element = $("#list").dxList({
        dataSource: ds,
        selectionMode: "multiple",
        selectAllMode: "allPages"
    });

    var instance = $element.dxList("instance");
    assert.equal(loading.callCount, 1, "one load during creation");

    instance.selectAll();

    assert.deepEqual(instance.option("selectedItems"), items, "selected items is correct");
    assert.equal(loading.callCount, 2, "one load during select all");

    instance.unselectAll();

    assert.deepEqual(instance.option("selectedItems"), [], "selected items is empty");
    assert.equal(loading.callCount, 2, "no load during unselect all");
});

QUnit.module("selection");

QUnit.test("unselectItem for last item if 'allPages' selectAllMode", function(assert) {
    var items = [1, 2, 3, 4, 5];
    var loading = sinon.spy();
    var ds = new DataSource({
        store: items,
        pageSize: 2,
        paginate: true
    });
    ds.store().on("loading", loading);

    var $element = $("#list").dxList({
        selectedItems: [1],
        dataSource: ds,
        pageLoadMode: "nextButton",
        showSelectionControls: true,
        selectionMode: "all",
        selectAllMode: "allPages"
    });

    var instance = $element.dxList("instance");
    assert.equal(loading.callCount, 1, "one load during creation");

    //act
    instance.unselectItem(0);

    //assert
    assert.equal(loading.callCount, 1, "no load during unselect last item");
    assert.deepEqual(instance.option("selectedItems"), [], "selected items is empty");
});

QUnit.test("change selectedItemKeys to invisible items should perform load with filter", function(assert) {
    var items = [1, 2, 3, 4, 5];
    var ds = new DataSource({
        store: {
            type: "array",
            key: "this",
            data: items,
            onLoading: loading
        },
        pageSize: 2,
        paginate: true
    });

    var $element = $("#list").dxList({
        dataSource: ds,
        selectionMode: "multiple"
    });

    var instance = $element.dxList("instance");
    var loading = sinon.spy();
    ds.store().on("loading", loading);

    //act
    instance.option("selectedItemKeys", [4]);

    //assert
    assert.equal(loading.callCount, 1, "one load during change selectedRowKeys");
    assert.deepEqual(loading.lastCall.args[0].filter, ["this", "=", 4], "load during change selectedRowKeys");
    assert.deepEqual(instance.option("selectedItems"), [4], "selected items is empty");
});

QUnit.test("selectedItems should not be removed if items won't loaded", function(assert) {
    var items = [1, 2, 3, 4, 5];
    var ds = new DataSource({
        store: items,
        pageSize: 2,
        paginate: true
    });

    var $element = $("#list").dxList({
        dataSource: ds,
        pageLoadMode: "nextButton",
        selectedItems: items.slice(),
        selectionMode: "multiple"
    });

    $element.find(".dx-list-next-button .dx-button").trigger("dxclick");
    assert.deepEqual($element.dxList("option", "selectedItems"), items, "selected items is correct");
});

QUnit.test("selectedItems should be cleaned after pulldown", function(assert) {
    var items = [1, 2, 3, 4, 5];
    var ds = new DataSource({
        store: items,
        pageSize: 2,
        paginate: true
    });

    var $element = $("#list").dxList({
        pullRefreshEnabled: true,
        dataSource: ds,
        selectedItems: items.slice(),
        selectionMode: "multiple"
    });

    $element.dxScrollView("option", "onPullDown")();
    assert.deepEqual($element.dxList("option", "selectedItems"), [], "selected items were cleaned");
});

QUnit.test("selectedItems should not be cleaned after reordering if store key specified", function(assert) {
    var items = [{ id: 1, text: "1" }, { id: 2, text: "2" }, { id: 3, text: "3" }];

    var listInstance = $("#list").dxList({
        dataSource: new ArrayStore({
            key: "id",
            data: items
        }),
        selectionMode: "all"
    }).dxList("instance");

    listInstance.selectItem(0);

    var item0 = $("#list").find(toSelector(LIST_ITEM_CLASS)).eq(0).get(0),
        item1 = $("#list").find(toSelector(LIST_ITEM_CLASS)).eq(1).get(0);

    listInstance.reorderItem(item0, item1);
    assert.equal(listInstance.option("selectedItems")[0], items[0], "first item is selected");
});

//T525081
QUnit.test("selection works well after clean all selected items and selectAllMode is 'allPages'", function(assert) {
    var items = [1, 2, 3],
        selectionChangedSpy = sinon.spy();

    var listInstance = $("#list").dxList({
        dataSource: new ArrayStore({
            key: "id",
            data: items
        }),
        selectionMode: "all",
        showSelectionControls: true,
        selectAllMode: "allPages",
        onSelectionChanged: selectionChangedSpy
    }).dxList("instance");

    listInstance.selectItem(0);
    listInstance.unselectItem(0);
    listInstance.selectItem(0);

    assert.equal(selectionChangedSpy.callCount, 3, "'selectionChanged' event has been fired 3 times");
});

//T567757
QUnit.test("Selecting all filtered items when selectAllMode is 'allPages'", function(assert) {
    //arrange
    var items = [1, 2, 3, 4, 5],
        $selectAll,
        ds = new DataSource({
            store: items,
            pageSize: 2,
            paginate: true,
            searchValue: "1"
        });

    var instance = $("#list").dxList({
        dataSource: ds,
        showSelectionControls: true,
        selectionMode: "all",
        selectAllMode: "allPages"
    }).dxList("instance");

    //act
    instance.selectItem(0);

    //assert
    $selectAll = $("#list").find(".dx-list-select-all-checkbox");
    assert.ok($selectAll.hasClass("dx-checkbox-checked"), "selectAll checkbox is checked");
    assert.deepEqual(instance.option("selectedItems"), [1], "selected items");

    //act
    ds.searchValue("");
    ds.load();

    //assert
    $selectAll = $("#list").find(".dx-list-select-all-checkbox");
    assert.ok($selectAll.hasClass("dx-checkbox-indeterminate"), "selectAll checkbox is indeterminate");
});

var LIST_ITEM_SELECTED_CLASS = "dx-list-item-selected";

QUnit.module("selecting in grouped list", {
    beforeEach: function() {
        this.data = [
            {
                key: 'first',
                items: [{ a: 0 }, { a: 1 }, { a: 2 }]
            },
            {
                key: 'second',
                items: [{ a: 3 }, { a: 4 }, { a: 5 }]
            },
            {
                key: 'third',
                items: [{ a: 6 }, { a: 7 }, { a: 8 }]
            }
        ];
        this.selection = [
            { group: 0, item: 0 },
            { group: 0, item: 2 },
            { group: 1, item: 1 },
            { group: 2, item: 2 }
        ];
        this.itemsSelection = [
            {
                key: 'first',
                items: [this.data[0].items[0], this.data[0].items[2]]
            },
            {
                key: 'second',
                items: [this.data[1].items[1]]
            },
            {
                key: 'third',
                items: [this.data[2].items[2]]
            }
        ];
    }
});

var LIST_GROUP_CLASS = "dx-list-group";

QUnit.test("selectItem by node should add item to selectedItems", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance");

    var $groups = $list.find(toSelector(LIST_GROUP_CLASS));

    var selectItem = function(group, item) {
        list.selectItem($groups.eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item));
    };

    $.each(this.selection, function(index, value) {
        selectItem(value.group, value.item);
    });

    var selected = list.option("selectedItems");

    assert.deepEqual(selected, this.itemsSelection, "selection must be equal");
});

QUnit.test("selectItem by index should add item to selectedItems", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance");

    var selectItem = function(group, item) {
        list.selectItem({ group: group, item: item });
    };

    $.each(this.selection, function(index, value) {
        selectItem(value.group, value.item);
    });

    var selected = list.option("selectedItems");

    assert.deepEqual(selected, this.itemsSelection, "selection must be equal");
});

QUnit.test("selectItem by itemData should add item to selectedItems", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance"),
        that = this;

    var selectItem = function(group, item) {
        list.selectItem(that.data[group].items[item]);
    };

    $.each(this.selection, function(index, value) {
        selectItem(value.group, value.item);
    });

    var selected = list.option("selectedItems");

    assert.deepEqual(selected, this.itemsSelection, "selection must be equal");
});

QUnit.test("selectItem by itemElement should add item to selectedItems", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance");

    list.selectItem($("<div>"));
    assert.equal(list.option("selectedItems").length, 0, "selection must be empty");
});

QUnit.test("unselectItem should remove item from selectedItems", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance");

    var selectItem = function(group, item) {
        list.selectItem({ group: group, item: item });
    };
    var unselectItem = function(group, item) {
        list.unselectItem({ group: group, item: item });
    };

    $.each(this.selection, function(index, value) {
        selectItem(value.group, value.item);
        unselectItem(value.group, value.item);
    });

    var selected = list.option("selectedItems");

    assert.deepEqual(selected, [], "selection must be equal");
});

QUnit.test("isItemSelected should reflect current item state", function(assert) {
    var data = [
        {
            key: 'first',
            items: [{ a: 0 }]
        },
        {
            key: 'second',
            items: [{ a: 0 }]
        }
    ];

    var $list = $("#templated-list").dxList({
            items: data,
            grouped: true,
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance");

    var $items = $list.find(toSelector(LIST_ITEM_CLASS));

    list.selectItem($items.eq(1));
    assert.equal(list.isItemSelected($items.eq(1)), true, "isItemSelected return proper state");

    list.unselectItem($items.eq(1));
    assert.equal(list.isItemSelected($items.eq(1)), false, "isItemSelected return proper state");
});

QUnit.test("selection should be same when list refresh", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance");

    var groupItem = function(group, item) {
        return $list.find(toSelector(LIST_GROUP_CLASS)).eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item);
    };
    var selectItem = function(group, item) {
        list.selectItem(groupItem(group, item));
    };

    $.each(this.selection, function(index, value) {
        selectItem(value.group, value.item);
    });

    list._refresh();

    $.each(this.selection, function(index, value) {
        assert.ok(groupItem(value.group, value.item).hasClass(LIST_ITEM_SELECTED_CLASS), "class rendered");
    });
});

QUnit.test("selection should be cleared after grouped option is changed", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance");

    var $groups = $list.find(toSelector(LIST_GROUP_CLASS));

    var selectItem = function(group, item) {
        list.selectItem($groups.eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item));
    };

    $.each(this.selection, function(index, value) {
        selectItem(value.group, value.item);
    });

    list.option("grouped", false);

    assert.equal(list.option("selectedItems").length, 0, "should not be items in selectedItems");
    assert.equal($list.find(toSelector(LIST_ITEM_SELECTED_CLASS)).length, 0, "should not be selected elements");
});

QUnit.test("deleteItem should change selected items", function(assert) {
    var toDelete = [
            { group: 0, item: 1 },
            { group: 1, item: 1 },
            { group: 2, item: 1 }
        ],
        itemsSelection = [
            {
                key: 'first',
                items: [{ a: 0 }, { a: 2 }]
            },
            {
                key: 'third',
                items: [{ a: 8 }]
            }
        ];


    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance");

    var groups = function() {
        return $list.find(toSelector(LIST_GROUP_CLASS));
    };
    var selectItem = function(group, item) {
        list.selectItem(groups().eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item));
    };
    var deleteItem = function(group, item) {
        list.deleteItem(groups().eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item));
    };

    $.each(this.selection, function(_, value) {
        selectItem(value.group, value.item);
    });
    $.each(toDelete, function(_, value) {
        deleteItem(value.group, value.item);
    });

    assert.deepEqual(list.option("selectedItems"), itemsSelection, "item not deleted");
});

QUnit.test("item should be selectable by click on it in the grouped list", function(assert) {
    var list = $("#templated-list").dxList({
            items: [
                { key: "first", items: [{ text: "item 1" }] }
            ],
            grouped: true,
            selectionMode: "multiple",
            keyExpr: "text"
        }).dxList("instance"),
        $items = list.itemElements();

    $items.eq(0).trigger("dxclick");

    assert.ok($items.eq(0).hasClass("dx-list-item-selected"), "item became selected");
});


QUnit.module("selecting in grouped list with single mode", {
    beforeEach: function() {
        this.data = [
            {
                key: 'first',
                items: [{ a: 0 }, { a: 1 }, { a: 2 }]
            },
            {
                key: 'second',
                items: [{ a: 3 }, { a: 4 }, { a: 5 }]
            },
            {
                key: 'third',
                items: [{ a: 6 }, { a: 7 }, { a: 8 }]
            }
        ];
        this.selection = [
            { group: 0, item: 0 },
            { group: 0, item: 2 },
            { group: 1, item: 1 },
            { group: 2, item: 2 }
        ];
        this.itemsSelection = [
            {
                key: 'first',
                items: [this.data[0].items[0], this.data[0].items[2]]
            },
            {
                key: 'second',
                items: [this.data[1].items[1]]
            },
            {
                key: 'third',
                items: [this.data[2].items[2]]
            }
        ];
    }
});

QUnit.test("selectedItem should select only one item", function(assert) {
    var itemsSelection = [
        {
            key: 'third',
            items: [{ a: 8 }]
        }
    ];

    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectionMode: 'single'
        }),
        list = $list.dxList("instance");

    var groups = function() {
        return $list.find(toSelector(LIST_GROUP_CLASS));
    };
    var selectItem = function(group, item) {
        list.selectItem(groups().eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item));
    };

    $.each(this.selection, function(_, value) {
        selectItem(value.group, value.item);
    });

    assert.deepEqual(list.option("selectedItems"), itemsSelection, "selected only one item");
});

QUnit.test("selectedItems should accept only one item", function(assert) {
    var itemsSelection = [
        {
            key: 'first',
            items: [{ a: 0 }]
        }
    ];

    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            selectedItems: this.itemsSelection,
            selectionMode: 'single'
        }),
        list = $list.dxList("instance");

    assert.deepEqual(list.option("selectedItems"), itemsSelection, "selected only one item");

    list.option("selectedItems", this.itemsSelection);
    assert.deepEqual(list.option("selectedItems"), itemsSelection, "selected only one item");
});


QUnit.module("selecting in grouped list with dataSource");

QUnit.test("selection should hold selection after dataSource filtering (T474406)", function(assert) {
    var items = [
        { key: 'first', text: 'a' },
        { key: 'second', text: 'b' }
    ];
    var dataSource = new DataSource({
        store: items,
        group: "key",
        searchOperation: "contains",
        searchExpr: "text"
    });

    var $list = $("#templated-list").dxList({
            dataSource: dataSource,
            grouped: true,
            keyExpr: "text",
            selectedItemKeys: ["b"],
            selectionMode: 'multiple'
        }),
        list = $list.dxList("instance");

    dataSource.searchValue("a");
    dataSource.load();

    var groups = function() {
        return $list.find(toSelector(LIST_GROUP_CLASS));
    };
    var selectItem = function(group, item) {
        list.selectItem(groups().eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item));
    };

    selectItem(0, 0);

    assert.deepEqual(list.option("selectedItemKeys"), ["a", "b"]);
});


QUnit.module("reordering in grouped items", {
    beforeEach: function() {
        this.data = [
            {
                key: 'first',
                items: [{ a: 0 }, { a: 1 }, { a: 2 }]
            },
            {
                key: 'second',
                items: [{ a: 3 }, { a: 4 }, { a: 5 }]
            }
        ];
        this.movedItem = { group: 0, item: 1 };
        this.destinationItem = { group: 1, item: 1 };
        this.movedItems = [
            {
                key: 'first',
                items: [{ a: 0 }, { a: 2 }]
            },
            {
                key: 'second',
                items: [{ a: 3 }, { a: 1 }, { a: 4 }, { a: 5 }]
            }
        ];
    }
});

QUnit.test("reorderItem should swap items by node", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true
        }),
        list = $list.dxList("instance");

    var groups = function() {
        return $list.find(toSelector(LIST_GROUP_CLASS));
    };
    var item = function(group, item) {
        return groups().eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item).get(0);
    };

    var item01 = item(0, 1),
        item11 = item(1, 1);

    list.reorderItem(item01, item11);
    assert.equal(item01, item(1, 1));
    assert.equal(item11, item(1, 2));
});

QUnit.test("reorderItem should swap items by index", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true
        }),
        list = $list.dxList("instance");

    var groups = function() {
        return $list.find(toSelector(LIST_GROUP_CLASS));
    };
    var item = function(group, item) {
        return groups().eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item).get(0);
    };

    var item01 = item(0, 1),
        item11 = item(1, 1);

    list.reorderItem(this.movedItem, this.destinationItem);
    assert.equal(item01, item(1, 1));
    assert.equal(item11, item(1, 2));
});

QUnit.test("reorderItem should swap items by node within one group", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true
        }),
        list = $list.dxList("instance");

    var groups = function() {
        return $list.find(toSelector(LIST_GROUP_CLASS));
    };
    var item = function(group, item) {
        return groups().eq(group).find(toSelector(LIST_ITEM_CLASS)).eq(item).get(0);
    };

    var item11 = item(1, 1),
        item12 = item(1, 2);

    list.reorderItem(item11, item12);
    assert.equal(item11, item(1, 2));
    assert.equal(item12, item(1, 1));
});

QUnit.test("reorderItem should swap last with first items in items option", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true
        }),
        list = $list.dxList("instance");

    list.reorderItem(this.movedItem, this.destinationItem);
    assert.deepEqual(list.option("items"), this.movedItems, "items option changed");
});

QUnit.test("onItemReordered should be fired if items reordered", function(assert) {
    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            editEnabled: true,
            onItemReordered: function(args) {
                assert.deepEqual(args.fromIndex, { group: 0, item: 1 }, "correct from index");
                assert.deepEqual(args.toIndex, { group: 1, item: 1 }, "correct to index");
            }
        }),
        list = $list.dxList("instance");

    var item = function(group, item) {
        return $list.find(toSelector(LIST_GROUP_CLASS)).eq(group)
            .find(toSelector(LIST_ITEM_CLASS)).eq(item)
            .get(0);
    };

    list.reorderItem(item(0, 1), item(1, 1));
});

QUnit.test("selection should be updated after items reordered", function(assert) {
    var selection = [
        {
            key: 'second',
            items: [this.data[0].items[1], this.data[1].items[1]]
        }
    ];

    var $list = $("#templated-list").dxList({
            items: this.data,
            grouped: true,
            selectedItems: [
                {
                    key: 'first',
                    items: [this.data[0].items[1]]
                },
                {
                    key: 'second',
                    items: [this.data[1].items[1]]
                }
            ],
            editEnabled: true,
            selectionMode: "multiple"
        }),
        list = $list.dxList("instance");

    list.reorderItem(this.movedItem, this.destinationItem);
    assert.deepEqual(list.option("selectedItems"), selection, "selectedItems option updated");
});
